﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using Celeriq.Common;

namespace Celeriq.Utilities
{
	/// <summary>
	/// Handles all the user permission
	/// </summary>
	public static class UserDomain
	{
		private static List<SystemCredentials> _userList = null;
		private static object _locker = new object();

		/// <summary>
		/// The user list
		/// </summary>
		public static ReadOnlyCollection<SystemCredentials> UserList
		{
			get
			{
				lock (_locker)
				{
					if (_userList == null)
					{
						_userList = LoadUserFile();
					}
					return _userList.AsReadOnly();
				}
			}
		}

		/// <summary>
		/// Add a user to the system
		/// </summary>
		public static bool AddUser(SystemCredentials user)
		{
			lock (_locker)
			{
				if (_userList == null) return false;

				if (string.IsNullOrEmpty(user.UserName))
				{
					throw new Exception("The user name must be set.");
				}

				if (_userList.Count(x => x.UserName == user.UserName) == 0)
				{

					//if (!SecurityHelper.IsValidPassword(user.Password))
					//{
					//	throw new Exception("The password does not meet length or complexity requirements.");
					//}

					_userList.Add(user);
					SaveUserFile();
					return true;
				}
				else
				{
					throw new Exception("The user already exists.");
				}

				return false;
			}
		}

		/// <summary>
		/// Delete a user from the system
		/// </summary>
		public static bool DeleteUser(SystemCredentials user)
		{
			lock (_locker)
			{
				if (user.UserName == "root")
				{
					throw new Exception("The root user cannot be deleted.");
				}

				if (_userList == null) return false;
				var q = _userList.FirstOrDefault(x => x.UserName == user.UserName);
				if (q != null)
				{
					_userList.Remove(q);
					SaveUserFile();
					return true;
				}
				return false;
			}
		}

		/// <summary>
		/// Delete a user from the system
		/// </summary>
		public static bool UpdateUser(SystemCredentials user)
		{
			lock (_locker)
			{
				if (_userList == null) return false;
				var q = _userList.FirstOrDefault(x => x.UserName == user.UserName);
				if (q != null)
				{
					_userList.Remove(q);
					_userList.Add(user);
					SaveUserFile();
					return true;
				}
				return false;
			}
		}

		/// <summary>
		/// Loads the user file off disk
		/// </summary>
		private static List<SystemCredentials> LoadUserFile()
		{
			lock (_locker)
			{
				var userFile = ConfigurationSettings.GetUserFile();
				if (!File.Exists(userFile))
				{
					//TODO: This is a security risk to create the file if one does not exist!!
					_userList = new List<SystemCredentials>();
					_userList.Add(new SystemCredentials() { UserName = "root", Password = "password", UserId = Guid.NewGuid() });
					SaveUserFile();
					System.Threading.Thread.Sleep(500);
					_userList = new List<SystemCredentials>();
					//throw new Exception("There are no configured users.");
					Logger.LogWarning("There are no configured users.");
				}

				try
				{
					var retval = new List<SystemCredentials>();
					var xml = SecurityHelper.DecryptFromDisk(userFile);
					var document = new System.Xml.XmlDocument();
					document.LoadXml(xml);

					foreach (XmlNode node in document.DocumentElement.ChildNodes)
					{
						var name = XmlHelper.GetAttribute(node, "name", string.Empty);
						var password = XmlHelper.GetAttribute(node, "password", string.Empty);
						var id = XmlHelper.GetAttribute(node, "userid", Guid.NewGuid());
						retval.Add(new SystemCredentials() { UserName = name, Password = password, UserId = id });
					}

					Logger.LogInfo("User Loaded Count: " + retval.Count);

					return retval;
				}
				catch (Exception ex)
				{
					throw;
				}
			}
		}

		/// <summary>
		/// Saves the user file to disk
		/// </summary>
		private static void SaveUserFile()
		{
			lock (_locker)
			{
				if (_userList == null) return;
				try
				{
					var userFile = ConfigurationSettings.GetUserFile();

					//Create user file with default "root" user
					var document = new System.Xml.XmlDocument();
					document.LoadXml("<users></users>");

					foreach (var user in _userList)
					{
						var node = XmlHelper.AddElement(document.DocumentElement, "user");
						XmlHelper.AddAttribute(node, "name", user.UserName);
						XmlHelper.AddAttribute(node, "password", user.Password);
						XmlHelper.AddAttribute(node, "userid", user.UserId);
					}

					SecurityHelper.EncryptToDisk(userFile, document.OuterXml);
				}
				catch (Exception ex)
				{
					throw;
				}
			}
		}

	}
}